﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

/*- Pattern Responsibilities and Restrictions --
 * Definition: Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.
 * 
 * 1. LAYERING: A layer above data mapping layer. Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.
 *          - Ignorant of data access code
 *          - ** differs from traditional dal/data mapper **
 *          - Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers.
 * 2. READ: Client objects construct query specifications declaratively and submit them to Repository for satisfaction.
 *          - Declarative specification using QueryObject/Specification/Interpreter pattern
 *          - ** differs from traditional dal/data mapper, when specification is used **
 *          - ** same traditional dal/data mapper, when specification is used, when typical get-by-id like method is used **
 *          - LINQ Expressions can be considered as specification??
 *          - In such systems it can be worthwhile to build another layer of abstraction over the mapping layer where query construction code is concentrated
 *          - This becomes more important when there are a large number of domain classes or heavy querying. 
 *          - In these cases particularly, adding this layer helps minimize duplicate query logic.
 * 3. WRITE: (domain or data container) Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes.
 *          - ** same as traditional data mapper ** 
 *          - ** differs from traditional dal, as traditional dal can accept parameters in crud method ** 
 *          - it's insert/update/delete methods is restricted to have the data container object as the parameter 
 * 4. AGGREGATE ROOT
 *          ?? - Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer
 *          - ** same as traditional data mapper ** 
 *          - ** differs from traditional dal, as tradional dal don't let travanse via aggregate root **
 *          - Domain driven design/development
 *          - Adding in-memory order.OderDetails.Add ( new OrderDetails()) would insert the corresponding order details in database by OrderRepository.Insert (order) call.
 *  5. IT'S NOT ABOUT
 *          - InsertOnSubmit + SaveChages() operation, which is the responsibility of Unit Of Work pattern.
 *          
 * Data Container:- 
 * Advanced *:* with database and data container
 * OPTIONAL: Data container names can be different from database table
 * 
 * Data Container Fields:-
 * DON'T CARE: 1 data container field (value object/complex type) can be mapped to multiple database table fields
 * DON'T CARE: Extra fields are allowed on any side.
 * DON'T CARE: Field names can be different
 * DON'T CARE: Foreign key mapping to database fields
 * DON'T CARE: Computation can be implemented on fields (i.e. derived fields) 
 * DON'T CARE: Validation logic (i.e. email/phone format etc) on data fields
 * 
 * CRUD Method :-
 * REQUIRED: Data container and CRUD methods are placed in different class
 * OPTIONAL: Insert/Update method type: instance/static
 * OPTIONAL: Insert/Update method parameter - object
 * OPTIONAL: Delete/Get method type: instance/static
 * OPTIONAL: Delete/Get method parameter: By Id/Object etc
 * 
 * Business Logic :-
 * OPTIONAL: Complex computational logic (non-field level) can be included, along with any domain layer pattern
 * OPTIONAL: Transactional/workflow logic can be included, along with any domain layer pattern
 */
namespace RepositorySample
{
    public class Company
    {
        public int CompanyId { get; set; }
        public string CompanyName { get; set; }
        public IList<Employee> Employees { get; set; }//3, foreign key child table
    }

    public class Task
    {
        public int TaskId { get; set; }
        public string TaskName { get; set; }
        public DateTime TaskStarted { get; set; }
        public DateTime TaskEnded { get; set; }
        public Employee TaskAssignedTo { get; set; }//2, foreign key parent table
    }

    public class Employee
    {
        public int EmployeeId { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public float MonthlySalary { get; set; }
        public IList<Task> Tasks { get; set; }//3, foreign key child tables/these fields can also be considered as the aggregate childs
        public Company Company { get; set; }//2, foreign key parent table/foreign key mapping 
        public int ReportsTo { get; set; }//we can also use the direct foreign key reference, if we wish//should be here??
        public Employee() {  }
    }

    public class EmployeeRepository
    {
        public void Insert(Employee employee) { throw new NotImplementedException(); }
        public void Update(Employee employee) { throw new NotImplementedException(); }

        public void Delete(int EmployeeId) { throw new NotImplementedException(); }
        public void Delete(Employee employee) { throw new NotImplementedException(); }

        public Employee GetById(int EmployeeId) { throw new NotImplementedException(); }
        
        public IList<Employee> GetByCompanyId(int companyId) { throw new NotImplementedException(); }//should be here?? Yes?
        public IList<Employee> GetByCompany(Company company) { throw new NotImplementedException(); }
    }
}
